home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / HyperMail102.lha / HyperMail / parse.c < prev    next >
C/C++ Source or Header  |  1995-06-18  |  17KB  |  713 lines

  1. /*
  2. ** Copyright (C) 1994, Enterprise Integration Technologies Corp.        
  3. ** All Rights Reserved.
  4. ** Kevin Hughes, kevinh@eit.com 
  5. ** 7/31/94
  6. */
  7.  
  8. #include "hypermail.h"
  9. #include "parse.h"
  10.  
  11. /* Parsing...the heart of Hypermail!
  12. ** This loads in the articles from stdin or a mailbox, adding the right
  13. ** field variables to the right structures. If readone is set, it will
  14. ** think anything it reads in is one article only.
  15. */
  16.  
  17. void loadheaders(mbox, use_stdin, readone)
  18.      char *mbox;
  19.      int use_stdin;
  20.      int readone;
  21. {
  22.     FILE *fp;
  23.     char name[NAMESTRLEN], email[MAILSTRLEN], date[DATESTRLEN],
  24.         msgid[MSGDSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
  25.         line[MAXLINE], tmpfrom[MAXLINE], fromdate[DATESTRLEN],
  26.         oldline[MAXLINE];
  27.     int num, isinheader, hassubject, hasdate, wasinreply;
  28.     struct body *bp;
  29.  
  30.     if (!strcmp(mbox, "NONE") || use_stdin)
  31.         fp = stdin;
  32.     else {
  33.         if ((fp = fopen(mbox, "r")) == NULL) {
  34.             sprintf(errmsg, "Couldn't open mail archive \"%s\".",
  35.             mbox);
  36.             progerr(NULL);
  37.         }
  38.     }
  39.  
  40.     if (readone)
  41.         num = bignum;
  42.     else
  43.         num = 0;
  44.     hassubject = 0;
  45.     hasdate = 0;
  46.     wasinreply = 0;
  47.     isinheader = 1;
  48.     inreply[0] = '\0';
  49.     tmpfrom[0] = '\0';
  50.     oldline[0] = '\0';
  51.     bp = NULL;
  52.     if (!readone) {
  53.         replylist = NULL;
  54.         subjectlist = NULL;
  55.         authorlist = NULL;
  56.         datelist = NULL;
  57.     }
  58.     if (showprogress && readone)
  59.         printf("Reading new header...\n");
  60.     if (showprogress && !readone) {
  61.         if (!strcmp(mbox, "NONE") || use_stdin)
  62.             printf("Loading mailbox...    ");
  63.         else
  64.             printf("Loading mailbox \"%s\"...    ", mbox);
  65.     }
  66.     while (fgets(line, MAXLINE, fp) != NULL) {
  67.         if (isinheader) {
  68.             if (!strncmp(line, "Received:", 9) ||
  69.             !strncmp(line, "Return-Path:", 12) ||
  70.             !strncmp(line, "Cc:", 3) ||
  71.             !strncmp(line, "X-", 2) ||
  72.             !strncmp(line, "Flags:", 6))
  73.                 continue;
  74.             if (!strncmp(line, "From ", 5))
  75.                 strcpy(fromdate, (char *) getfromdate(line));
  76.             else if (!strncmp(line, "Date:", 5)) {
  77.                 bp = (struct body *) addbody(bp, line);
  78.                 strcpy(date, (char *) getmaildate(line));
  79.                 hasdate = 1;
  80.             }
  81.             else if (!strncmp(line, "From:", 5)) {
  82.                 bp = (struct body *) addbody(bp, line);
  83.                 getname(line, name, email);
  84.             }
  85.             else if (!strncmp(line, "Message-Id:", 11)) {
  86.                 bp = (struct body *) addbody(bp, line);
  87.                 strcpy(msgid, (char *) getid(line));
  88.             }
  89.             else if (!strncmp(line, "Subject:", 8)) {
  90.                 bp = (struct body *) addbody(bp, line);
  91.                 strcpy(subject, (char *) getsubject(line));
  92.                 hassubject = 1;
  93.             }
  94.             else if (!strncmp(line, "In-Reply-To:", 12)) {
  95.                 bp = (struct body *) addbody(bp, line);
  96.                 strcpy(inreply, (char *) getreply(line));
  97.                 wasinreply = 1;
  98.             }
  99.             else if ((!strncmp(line, "    ", 4) ||
  100.             line[0] == '\t') &&
  101.             strchr(line, '<') && strchr(line, '>') &&
  102.             strchr(line, '@') && wasinreply) {
  103.                 bp = (struct body *) addbody(bp, line);
  104.                 strcpy(inreply, (char *) getreply(line));
  105.                 wasinreply = 0;
  106.             }
  107.             else if (!strncmp(line, "To:", 3))
  108.                 bp = (struct body *) addbody(bp, line);
  109.             else if (line[0] == '\n') {
  110.                 bp = (struct body *) addbody(bp, line);
  111.                 isinheader = 0;
  112.             }
  113.         }
  114.         else {
  115.             if (!strncmp(line, "From ", 5)) {
  116.                 if (readone)
  117.                     continue;
  118.                 if (strstr(oldline,
  119.                 "Forwarded message:")) {
  120.                     oldline[0] = '\0';
  121.                     continue;
  122.                 }
  123.                 isinheader = 1;
  124.                 wasinreply = 0;
  125.                 if (!hassubject)
  126.                     strcpy(subject, NOSUBJECT);
  127.                 else
  128.                     hassubject = 1;
  129.                 if (!hasdate)
  130.                     strcpy(date, NODATE);
  131.                 else
  132.                     hasdate = 1;
  133.                 if (inreply[0] == '\0')
  134.                     oneunre(inreply, subject);
  135.                 while (rmlastlines(bp));
  136.                 addhash(num, date, name, email, msgid, subject, inreply, fromdate, bp);
  137.                 authorlist = (struct header *)
  138.                 addheader(authorlist, num, name, subject, date, 1);
  139.                 subjectlist = (struct header *)
  140.                 addheader(subjectlist, num, name, unre(subject), date, 0);
  141.                 datelist = (struct header *)
  142.                 addheader(datelist, num, name, subject, fromdate, 2);
  143.                 strcpy(fromdate, (char *) getfromdate(line));
  144.  
  145.                 bp = NULL;
  146.                 num++;
  147.                 if (!(num % 10) && showprogress && !readone) {
  148.                     printf("\b\b\b\b%4d", num);
  149.                     fflush(stdout);
  150.                 }
  151.                 inreply[0] = '\0';
  152.             }
  153.             else
  154.                 bp = (struct body *) addbody(bp, line);
  155.         }
  156.         strcpy(oldline, line);
  157.     }
  158.     if (!isinheader) {
  159.         if (!hassubject)
  160.             strcpy(subject, NOSUBJECT);
  161.         if (!hasdate)
  162.             strcpy(date, NODATE);
  163.         if (inreply[0] == '\0')
  164.             oneunre(inreply, subject);
  165.         while (rmlastlines(bp));
  166.         addhash(num, date, name, email, msgid, subject, inreply,
  167.         fromdate, bp);
  168.         authorlist = (struct header *)
  169.         addheader(authorlist, num, name, subject, date, 1);
  170.         subjectlist = (struct header *)
  171.         addheader(subjectlist, num, name, unre(subject), date, 0);
  172.         datelist = (struct header *) addheader(datelist, num, name,
  173.         subject, fromdate, 2);
  174.         num++;
  175.     }
  176.     if (showprogress && !readone)
  177.         printf("\b\b\b\b%4d articles.\n", num);
  178.  
  179.     if (!readone)
  180.         bignum = num - 1;
  181.     fclose(fp);
  182.  
  183.     crossindex();
  184.  
  185.     threadlist = NULL;
  186.     printedthreadlist = NULL;
  187.     crossindexthread1(datelist);
  188. }
  189.  
  190. /* All this does is get all the relevant header information from the
  191. ** comment fields in existing archive files. Everything is loaded into
  192. ** structures in the exact same way as if articles were being read from
  193. ** stdin or a mailbox.
  194. */
  195.  
  196. void loadoldheaders(dir)
  197.      char *dir;
  198. {
  199.     FILE *fp;
  200.     char name[NAMESTRLEN], email[MAILSTRLEN], date[DATESTRLEN],
  201.         msgid[MSGDSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
  202.         line[MAXLINE], fromdate[DATESTRLEN], filename[MAXFILELEN];
  203.     int num;
  204.     struct body *bp;
  205.  
  206.     num = 0;
  207.     sprintf(filename, "%s%s%.4d.html", dir,
  208.     (dir[strlen(dir) - 1] == '/') ? "" : "/", num);
  209.  
  210.     bp = NULL;
  211.     bp = (struct body *) addbody(bp, "\0");
  212.  
  213.     authorlist = subjectlist = datelist = NULL;
  214.  
  215.     if (showprogress)
  216.         printf("Reading old headers...    ");
  217.     while ((fp = fopen(filename, "r")) != NULL) {
  218.  
  219.         fgets(line, MAXLINE, fp);
  220.         strcpy(fromdate, (char *) getvalue(line));
  221.         fgets(line, MAXLINE, fp);
  222.         strcpy(date, (char *) getvalue(line));
  223.         fgets(line, MAXLINE, fp);
  224.         strcpy(name, (char *) getvalue(line));
  225.         fgets(line, MAXLINE, fp);
  226.         strcpy(email, (char *) getvalue(line));
  227.         fgets(line, MAXLINE, fp);
  228.         strcpy(subject, (char *) unconvchars(getvalue(line)));
  229.         fgets(line, MAXLINE, fp);
  230.         strcpy(msgid, (char *) getvalue(line));
  231.         fgets(line, MAXLINE, fp);
  232.         strcpy(inreply, (char *) unconvchars(getvalue(line)));
  233.  
  234.         fclose(fp);
  235.  
  236.         addhash(num, date, name, email, msgid, subject, inreply, fromdate, bp);
  237.         authorlist = (struct header *)
  238.         addheader(authorlist, num, name, subject, date, 1);
  239.         subjectlist = (struct header *)
  240.         addheader(subjectlist, num, name, unre(subject), date, 0);
  241.         datelist = (struct header *)
  242.         addheader(datelist, num, name, subject, fromdate, 2);
  243.  
  244.         num++;
  245.         if (!(num % 10) && showprogress) {
  246.             printf("\b\b\b\b%4d", num);
  247.             fflush(stdout);
  248.         }
  249.  
  250.         sprintf(filename, "%s%s%.4d.html", dir,
  251.         (dir[strlen(dir) - 1] == '/') ? "" : "/", num);
  252.     }
  253.     if (showprogress)
  254.         printf("\b\b\b\b%4d articles.\n", num);
  255.  
  256.     if (!num)
  257.         bignum = 0;
  258.     else
  259.         bignum = num;
  260. }
  261.  
  262. /* Adds a "Next:" link in the proper article, after the archive has been
  263. ** incrementally updated.
  264. */
  265.  
  266. void fixnextheader(dir, num)
  267.      char *dir;
  268.      int num;
  269. {
  270.     char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
  271.         email[MAILSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
  272.         date[DATESTRLEN], fromdate[DATESTRLEN], msgid[MSGDSTRLEN];
  273.     struct body *bp, *status;
  274.     FILE *fp;
  275.  
  276.     sprintf(filename, "%s%s%.4d.html", dir,
  277.     (dir[strlen(dir) - 1] == '/') ? "" : "/", num);
  278.  
  279.     bp = NULL;
  280.     if ((fp = fopen(filename, "r")) != NULL) {
  281.         while ((fgets(line, MAXLINE, fp)) != NULL)
  282.             bp = (struct body *) addbody(bp, line);
  283.     }
  284.     else
  285.         return;
  286.     fclose(fp);
  287.  
  288.     if ((fp = fopen(filename, "w+")) != NULL)
  289.         while (bp != NULL) {
  290.             fprintf(fp, "%s", bp->line);
  291.             if (!strncmp(bp->line, "<!-- next=", 10)) {
  292.  
  293.                 status = (struct body *) hashnumlookup(num + 1,
  294.                 name, email, subject, inreply, date, fromdate,
  295.                 msgid);
  296.                 if (status != NULL) {
  297.                 fprintf(fp, "<li> <b>Next message:</b> ");
  298.                 fprintf(fp,
  299.                 "<a href=\"%.4d.html\">%s: \"%s\"</a>\n",
  300.                 num + 1, name, convchars(subject));
  301.                 }
  302.  
  303.             }
  304.             bp = bp->next;
  305.         }
  306.     fclose(fp);
  307. }
  308.  
  309. /* Adds a "Reply:" link in the proper article, after the archive has been
  310. ** incrementally updated.
  311. */
  312.  
  313. void fixreplyheader(dir, num)
  314.      char *dir;
  315.      int num;
  316. {
  317.     int replynum, subjmatch;
  318.     char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
  319.         email[MAILSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
  320.         date[DATESTRLEN], fromdate[DATESTRLEN], msgid[MSGDSTRLEN],
  321.         name2[NAMESTRLEN], subject2[SUBJSTRLEN];
  322.     struct body *bp, *status;
  323.     FILE *fp;
  324.  
  325.     status = (struct body *) hashnumlookup(num,
  326.     name, email, subject, inreply, date, fromdate, msgid);
  327.     if (status == NULL || inreply[0] == '\0')
  328.         return;
  329.     if (inreply[0] != '\0') {
  330.         replynum = hashreplylookup(inreply, name2, subject2,
  331.         &subjmatch);
  332.         if (replynum == -1)
  333.             return;
  334.     }
  335.  
  336.     sprintf(filename, "%s%s%.4d.html", dir,
  337.     (dir[strlen(dir) - 1] == '/') ? "" : "/", replynum);
  338.  
  339.     bp = NULL;
  340.     if ((fp = fopen(filename, "r")) != NULL) {
  341.         while ((fgets(line, MAXLINE, fp)) != NULL)
  342.             bp = (struct body *) addbody(bp, line);
  343.     }
  344.     else
  345.         return;
  346.     fclose(fp);
  347.  
  348.     if ((fp = fopen(filename, "w+")) != NULL)
  349.         while (bp != NULL) {
  350.             if (!strncmp(bp->line, "<!-- reply", 10)) {
  351.                 fprintf(fp, "<li> <b>Reply:</b> ");
  352.                 fprintf(fp, "<a href=\"%.4d.html\">", num);
  353.                 fprintf(fp, "%s: \"%s\"</a>\n",
  354.                 name, convchars(subject));
  355.             }
  356.             fprintf(fp, "%s", bp->line);
  357.             bp = bp->next;
  358.         }
  359.     fclose(fp);
  360. }
  361.  
  362. /* Adds a "Next in thread:" link in the proper article, after the archive
  363. ** has been incrementally updated.
  364. */
  365.  
  366. void fixthreadheader(dir, num)
  367.      char *dir;
  368.      int num;
  369. {
  370.     int threadnum;
  371.     char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
  372.         subject[SUBJSTRLEN];
  373.     struct body *bp;
  374.     struct reply *rp;
  375.     FILE *fp;
  376.  
  377.     for (rp = threadlist; rp != NULL; rp = rp->next)
  378.         if (rp->next != NULL && rp->next->msgnum == num &&
  379.         rp->msgnum != -1) {
  380.             threadnum = rp->msgnum;
  381.             strcpy(name, rp->next->name);
  382.             strcpy(subject, rp->next->subject);
  383.             break;
  384.         }
  385.     if (rp == NULL)
  386.         return;
  387.  
  388.     sprintf(filename, "%s%s%.4d.html", dir,
  389.     (dir[strlen(dir) - 1] == '/') ? "" : "/", threadnum);
  390.  
  391.     bp = NULL;
  392.     if ((fp = fopen(filename, "r")) != NULL) {
  393.         while ((fgets(line, MAXLINE, fp)) != NULL)
  394.             bp = (struct body *) addbody(bp, line);
  395.     }
  396.     else
  397.         return;
  398.     fclose(fp);
  399.  
  400.     if ((fp = fopen(filename, "w+")) != NULL)
  401.         while (bp != NULL) {
  402.             fprintf(fp, "%s", bp->line);
  403.             if (!strncmp(bp->line, "<!-- nextthr", 12)) {
  404.                 fprintf(fp, "<li> <b>Next in thread:</b> ");
  405.                 fprintf(fp, "<a href=\"%.4d.html\">", num);
  406.                 fprintf(fp, "%s: \"%s\"</a>\n",
  407.                 name, convchars(subject));
  408.             }
  409.             bp = bp->next;
  410.         }
  411.     fclose(fp);
  412. }
  413.  
  414. /* Cross-indexes - adds to a list of replies. If a message is a reply to
  415. ** another, the number of the messge it's replying to is added to the list.
  416. ** This list is searched upon printing.
  417. */
  418.  
  419. void crossindex()
  420. {
  421.     int num, status, maybereply;
  422.     char name[NAMESTRLEN], subject[SUBJSTRLEN], email[MAILSTRLEN],
  423.         inreply[REPYSTRLEN], date[DATESTRLEN], fromdate[DATESTRLEN],
  424.         msgid[MSGDSTRLEN];
  425.  
  426.     num = 0;
  427.     replylist = NULL;
  428.  
  429.     while (hashnumlookup(num, name, email, subject, inreply,
  430.     date, fromdate, msgid) != NULL) {
  431.         if (inreply[0] != '\0') {
  432.             status = hashreplynumlookup(inreply, &maybereply);
  433.             if (status != -1)
  434.                 replylist = (struct reply *)
  435.                 addreply(replylist, status, num, name, subject,
  436.                 maybereply);
  437.         }
  438.         num++;
  439.     }
  440. }
  441.  
  442. /* First, print out the threads in order by date...
  443. ** Each message number is appended to a thread list. Threads and individual
  444. ** messages are separated by a -1.
  445. */
  446.  
  447. void crossindexthread1(hp)
  448.      struct header *hp;
  449. {
  450.         int hasreply;
  451.         struct reply *rp;
  452.  
  453.         if (hp != NULL) {
  454.                 crossindexthread1(hp->left);
  455.  
  456.                 for (hasreply = 0, rp = replylist; rp != NULL; rp = rp->next)
  457.                         if (rp->frommsgnum == hp->msgnum) {
  458.                                 hasreply = 1;
  459.                                 break;
  460.                         }
  461.  
  462.                 if (!hasreply && !wasprinted(printedthreadlist, hp->msgnum)) {
  463.             threadlist = (struct reply *)
  464.             addreply(threadlist, hp->msgnum, hp->msgnum,
  465.             hp->name, hp->subject, 0);
  466.                         crossindexthread2(hp->msgnum);
  467.             threadlist = (struct reply *)
  468.             addreply(threadlist, -1, -1, " ", " ", 0);
  469.         }
  470.  
  471.                 crossindexthread1(hp->right);
  472.         }
  473. }
  474.  
  475. /* Recursively checks for replies to replies to a message, etc.
  476. ** Replies are added to the thread list.
  477. */
  478.  
  479. void crossindexthread2(num)
  480.      int num;
  481. {
  482.         struct reply *rp;
  483.  
  484.         for (rp = replylist; rp != NULL; rp = rp->next)
  485.                 if (rp->msgnum == num) {
  486.             threadlist = (struct reply *)
  487.             addreply(threadlist, rp->frommsgnum, num,
  488.             rp->name, rp->subject, 0);
  489.                         printedlist = (struct printed *)
  490.                         markasprinted(printedthreadlist, rp->frommsgnum);
  491.                         crossindexthread2(rp->frommsgnum);
  492.                 }
  493. }
  494.  
  495. /* Grabs the date string from a Date: header.
  496. */
  497.  
  498. char *getmaildate(line)
  499.      char *line;
  500. {
  501.     int i;
  502.     char *c;
  503.     static char date[DATESTRLEN];
  504.  
  505.     c = (char *) strchr(line, ':');
  506.     if ((*(c + 1) && *(c + 1) == '\n') ||
  507.     (*(c + 2) && *(c + 2) == '\n')) {
  508.         strcpy(date, NODATE);
  509.         return date;
  510.     }
  511.     c += 2;
  512.     while (isspace(*c))
  513.         c++;
  514.     for (i = 0; *c && *c != '\n' && i < DATESTRLEN; c++)
  515.         date[i++] = *c;
  516.     date[i] = '\0';
  517.  
  518.     return date;
  519. }
  520.  
  521. /* Grabs the date string from a From article separator.
  522. */
  523.  
  524. char *getfromdate(line)
  525.      char *line;
  526. {
  527.     int i;
  528.     char *c;
  529.     static char tmpdate[DATESTRLEN];
  530.  
  531.     for (i = 0; days[i] != NULL && (c = (char *) strstr(line, days[i]))
  532.     == NULL; i++)
  533.         ;
  534.     if (days[i] == NULL)
  535.         tmpdate[0] = '\0';
  536.     else {
  537.         for (i = 0; *c && *c != '\n' && i < DATESTRLEN; c++)
  538.             tmpdate[i++] = *c;
  539.         tmpdate[i] = '\0';
  540.         if (tmpdate[16] != ':') {
  541.             tmpdate[16] = ':';
  542.             tmpdate[17] = '0';
  543.             tmpdate[18] = '0';
  544.             tmpdate[19] = ' ';
  545.             tmpdate[20] = thisyear[0];
  546.             tmpdate[21] = thisyear[1];
  547.             tmpdate[22] = thisyear[2];
  548.             tmpdate[23] = thisyear[3];
  549.             tmpdate[24] = '\0';
  550.         }
  551.         sprintf(tmpdate, "%s %s", tmpdate, timezonestr);
  552.         return tmpdate;
  553.     }
  554.  
  555.     return tmpdate;
  556. }
  557.  
  558. /* Grabs the name and email address from a From: header.
  559. ** This could get tricky; I've tried to keep it simple.
  560. */
  561.  
  562. void getname(line, name, email)
  563.      char *line;
  564.      char *name;
  565.      char *email;
  566. {
  567.     int i;
  568.     char *c;
  569.  
  570.     if ((c = (char *) strchr(line, '@')) == NULL) {
  571.         if (strchr(line, '(')) {
  572.             c = (char *) strchr(line, ':') + 1;
  573.             while (isspace(*c))
  574.                 c++;
  575.             for (i = 0; *c && *c != '(' && *c != ' ' &&
  576.             *c != '\n' && i < MAILSTRLEN; c++)
  577.                 email[i++] = *c;
  578.             email[i] = '\0';
  579.         }
  580.         else
  581.             strcpy(email, NOEMAIL);
  582.     }
  583.     else {
  584.         while (*c != ' ' && *c != '<')
  585.             c--;
  586.         c++;
  587.         for (i = 0; *c && *c != '>' && *c != ' ' && *c != '\n' &&
  588.         i < MAILSTRLEN;
  589.         c++)
  590.             email[i++] = *c;
  591.         email[i] = '\0';
  592.     }
  593.  
  594.     if (strchr(line, '<')) {
  595.         c = (char *) strchr(line, ':') + 1;
  596.         while (isspace(*c) || *c == '\"')
  597.             c++;
  598.     }
  599.     else if (strchr(line, '('))
  600.         c = (char *) strchr(line, '(') + 1;
  601.     else {
  602.         if (strcmp(email, NOEMAIL))
  603.             strcpy(name, email);
  604.         else
  605.             strcpy(name, NONAME);
  606.         return;
  607.     }
  608.  
  609.     for (i = 0; *c && *c != '<' && *c != '\"' && *c != ')' &&
  610.     *c != '(' && *c != '\n' && i < NAMESTRLEN; c++)
  611.         name[i++] = *c;
  612.     if (*c == '<' || *c == '(')
  613.         name[--i] = '\0';
  614.     else
  615.         name[i] = '\0';
  616. }
  617.  
  618. /* Grabs the message ID, like <...> from the Message-ID: header.
  619. */
  620.  
  621. char *getid(line)
  622.      char *line;
  623. {
  624.     int i;
  625.     char *c;
  626.     static char msgid[MSGDSTRLEN];
  627.  
  628.     c = (char *) strchr(line, '<') + 1;
  629.     for (i = 0; *c && *c != '>' && *c != '\n' && i < MSGDSTRLEN; c++) {
  630.         if (*c == '\\')
  631.             continue;
  632.         msgid[i++] = *c;
  633.     }
  634.     msgid[i] = '\0';
  635.  
  636.     return msgid;
  637. }
  638.  
  639. /* Grabs the subject from the Subject: header.
  640. */
  641.  
  642. char *getsubject(line)
  643.      char *line;
  644. {
  645.     int i;
  646.     char *c;
  647.     static char subject[SUBJSTRLEN];
  648.  
  649.     c = (char *) strchr(line, ':') + 2;
  650.     while (isspace(*c))
  651.         c++;
  652.     for (i = 0; *c && *c != '\n' && i < SUBJSTRLEN; c++)
  653.         subject[i++] = *c;
  654.     subject[i] = '\0';
  655.     for (i--; i >= 0 && isspace(subject[i]); i--)
  656.         subject[i] = '\0';
  657.  
  658.     if (subject[0] == NULL || isspace(subject[0]) || subject[0] == '\n' ||
  659.     !strcasecmp(subject, "Re:"))
  660.         strcpy(subject, NOSUBJECT);
  661.  
  662.     return subject;
  663. }
  664.  
  665. /* Grabs the message ID, or date, from the In-reply-to: header.
  666. ** Who knows what other formats are out there...
  667. */
  668.  
  669. char *getreply(line)
  670.      char *line;
  671. {
  672.     int i;
  673.     char *c;
  674.     static char reply[REPYSTRLEN];
  675.  
  676.     if ((c = (char *) strstr(line, "dated: ")) != NULL) {
  677.         c += 7;
  678.         for (i = 0; *c && *c != '.' && *c != '\n' && i < REPYSTRLEN;
  679.         c++)
  680.             reply[i++] = *c;
  681.         reply[i] = '\0';
  682.         return reply;
  683.     }
  684.  
  685.     if ((c = (char *) strchr(line, '<')) != NULL ) {
  686.         c++;
  687.         for (i = 0; *c && *c != '>' && *c != '\n' && i < MSGDSTRLEN;
  688.         c++) {
  689.             if (*c == '\\')
  690.                 continue;
  691.             reply[i++] = *c;
  692.         }
  693.         reply[i] = '\0';
  694.         return reply;
  695.     }
  696.  
  697.     if ((c = (char *) strstr(line, "sage of ")) != NULL) {
  698.         c += 8;
  699.         if (*c == '\"')
  700.             c++;
  701.         for (i = 0; *c && *c != '.' && *c != '\n' && *c != 'f' &&
  702.         i < REPYSTRLEN; c++)
  703.             reply[i++] = *c;
  704.         reply[i] = '\0';
  705.         if (*c == 'f')
  706.             reply[--i] = '\0';
  707.         return reply;
  708.     }
  709.  
  710.     reply[0] = '\0';
  711.     return reply;
  712. }
  713.